package com.app.manage.moudles.app.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import com.app.manage.components.CommonComponent;
import com.app.manage.moudles.app.dao.TAppServerDao;
import com.app.manage.moudles.app.dao.TAppVariDao;
import com.app.manage.moudles.app.entity.TAppServer;
import com.app.manage.moudles.app.entity.TAppVari;
import com.app.manage.moudles.app.po.AppServerPo;
import com.app.manage.moudles.app.vo.AppLogVo;
import com.app.manage.moudles.confs.constants.GroupEnums;
import com.app.manage.moudles.confs.constants.VariTypeEnums;
import com.app.manage.moudles.confs.dao.TGroupRelationDao;
import com.app.manage.moudles.confs.entity.TGroupRelation;
import com.app.manage.moudles.operate.service.OperateService;
import com.app.manage.moudles.server.entity.TServer;
import com.app.manage.utils.EmptyIPage;
import com.app.manage.utils.SFTPUtil;
import com.app.manage.utils.SshUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.app.manage.moudles.app.dao.TAppDao;
import com.app.manage.moudles.app.entity.TApp;
import com.app.manage.moudles.app.service.TAppService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (TApp)表服务实现类
 *
 * @author makejava
 * @since 2025-05-16 11:18:27
 */
@Service("tAppService")
@Transactional
public class TAppServiceImpl extends ServiceImpl<TAppDao, TApp> implements TAppService {


    @Resource
    private TGroupRelationDao groupRelationDao;

    @Resource
    private TAppVariDao tAppVariDao;

    @Resource
    private TGroupRelationDao getGroupRelationDao;

    @Resource
    private TAppServerDao appServerDao;

    @Resource
    private OperateService operateService;

    @Resource
    private CommonComponent commonComponent;

    @Override
    public Object pageData(Integer pageNum, Integer pageSize, TApp tApp) {
        //查询分组
        List<Integer>  groupApppIdList = new ArrayList<>();
        if(tApp.getLongGroup() != null){
            groupApppIdList = groupRelationDao.selectRelationIds(tApp.getLongGroup(),
                    GroupEnums.APP_GROUP.getType());
            if(CollectionUtil.isEmpty(groupApppIdList)){
                return new EmptyIPage();
            }
        }

        //查询服务器
        if(tApp.getAppServerId() != null){
            List<Integer>  serverAppIdList = appServerDao.findAppIdForServer(tApp.getAppServerId());
            if(CollectionUtil.isEmpty(serverAppIdList)){
                return new EmptyIPage();
            }
            if(CollectionUtil.isEmpty(groupApppIdList)){
                groupApppIdList = serverAppIdList;
            }else {
                groupApppIdList.retainAll(serverAppIdList);
            }
        }

        //分页查询数据
        LambdaQueryWrapper<TApp> query = new LambdaQueryWrapper<>();
        query.in(CollectionUtil.isNotEmpty(groupApppIdList),TApp::getId,groupApppIdList);
        query.like(StringUtils.isNotEmpty(tApp.getAppName()),TApp::getAppName,tApp.getAppName());
        query.like(StringUtils.isNotEmpty(tApp.getAppCode()),TApp::getAppCode,tApp.getAppCode());
        query.orderByDesc(TApp::getCreateTime);
        IPage<TApp> pageRes = page(Page.of(pageNum,pageSize),query);


        if(CollectionUtil.isEmpty(pageRes.getRecords())){
            return pageRes;
        }
        return pageRes;
    }

    @Override
    public String saveData(Map<String, Object> map) {
        TApp tApp = new TApp();
        //构建一个app对象
        Map<String,Object> appMap = BeanUtil.beanToMap(tApp);
        for(Map.Entry<String,Object> e : appMap.entrySet()){
            appMap.put(e.getKey(),map.get(e.getKey()));
            map.remove(e.getKey());
        }
        tApp = BeanUtil.toBean(appMap,TApp.class);
        //重复检查
        long count = count(new LambdaQueryWrapper<TApp>()
                .ne(tApp.getId() != null,TApp::getId,tApp.getId())
                .eq(TApp::getAppCode,tApp.getAppCode())
                .last(" limit 1"));
        if(count > 0){
            return "当前应用已经配置已经配置！";
        }

        //剩余的就是变量
        if(tApp.getId() == null){
            addApp(tApp,map);
        }else {
            updateApp(tApp,map);
        }


        return null;
    }

    @Override
    public <T>String removeBatch(List<T> idList) {
        remove(new LambdaQueryWrapper<TApp>().in(TApp::getId,idList));
        tAppVariDao.delete(new LambdaQueryWrapper<TAppVari>().in(TAppVari::getAppId,idList));
        getGroupRelationDao.delete(new LambdaQueryWrapper<TGroupRelation>()
                .in(TGroupRelation::getRelationId,idList)
                .eq(TGroupRelation::getRelationType,GroupEnums.APP_GROUP.getType())
        );
        appServerDao.delete(new LambdaQueryWrapper<TAppServer>().in(TAppServer::getAppId,idList));
        return null;
    }

    @Override
    public Object getAppById(Integer id) {
        TApp tApp = getById(id);
        //服务器列表
        List<Integer> serverIdList = appServerDao.findServerIdforApp(id);
        if(CollectionUtil.isNotEmpty(serverIdList)){
            tApp.setAppServers(serverIdList.stream()
                    .map(String::valueOf)  // 将 Integer 转换为 String
                    .collect(Collectors.joining(",")));
        }
        //分组
        tApp.setLongGroup(getGroupRelationDao.selectGroupId(id,GroupEnums.APP_GROUP.getType()));
        //变量
        Map<Integer,Map<String,Object>> varMap = findAppVaris(Arrays.asList(id));
        Map<String,Object>  map =  BeanUtil.beanToMap(tApp);
        if(CollectionUtil.isNotEmpty(varMap)){
            map.putAll(varMap.get(id));
        }

        return map;
    }

    @Override
    public Object getDetail(Integer id) {
        TApp tApp = getById(id);
        List<String> serverIpList = appServerDao.selectServerIpsByAppId(id);
        if(CollectionUtil.isNotEmpty(serverIpList)){
            tApp.setServerIpListStr(String.join(",",serverIpList));
        }
        tApp.setAppPath(tApp.getAppPath()+ File.separator+tApp.getJarName());
        tApp.setLongGroupName(getGroupRelationDao.selectGroupName(id,GroupEnums.APP_GROUP.getType()));
        Map<Integer,Map<String,Object>> varMap = findAppVaris(Arrays.asList(id));
        Map<String,Object>  map =  BeanUtil.beanToMap(tApp);
        if(CollectionUtil.isNotEmpty(varMap)){
            map.putAll(varMap.get(id));
        }
        return map;
    }

    @Override
    public AppLogVo getAppLogVo(Integer id) {

        return null;
    }

    @Override
    public Map<String, TApp> findAppByJarNames(List<String> jarNameList) {
        if(CollectionUtil.isEmpty(jarNameList)){
            return  new HashMap<>();
        }
        List<TApp> appList = list(
                new LambdaQueryWrapper<TApp>()
                .in(TApp::getJarName,jarNameList)
        );
        return new HashMap<String, TApp>(){{
            appList.forEach(o->{
                put(o.getJarName(),o);
            });
        }};
    }

    @Override
    public List<Map<String,Object>> listAppServerVo(Integer appId) {

        //查询应用-服务器
        List<AppServerPo> appServiceList =  appServerDao.listAppPo(Arrays.asList(appId));
        List<Map<String,Object>> list = new ArrayList<>();
        for (AppServerPo po : appServiceList){
            Map<String,Object> map = new HashMap<>();
            map.put("id",po.getId());
            map.put("serverIp",po.getServerIp());
            map.put("logPath",po.getLogPath());
            map.put("appPath",po.getAppPath());
            list.add(map);
        }

        return list;
    }

    @Override
    public String startCmd(List<Integer> appServerIdList) {
        List<AppServerPo> appServerPoList = appServerDao.listAppPoById(appServerIdList);
        //处理
        for (AppServerPo po : appServerPoList){
            String appPath = po.getAppPath().endsWith(File.separator)?po.getAppPath():po.getAppPath()+File.separator;
            String cmd = "cd "+appPath+" && "+po.getStartCmd();
            SshUtils.execForStr(po.getServerIp(),po.getLoginPort(),po.getLoginUser(),po.getLoginPwd(),
                    cmd);
        }
        return null;
    }


    @Override
    public String stopCmd(List<Integer> appServerIdList) {
        List<AppServerPo> appServerPoList = appServerDao.listAppPoById(appServerIdList);
        //处理
        for (AppServerPo po : appServerPoList){
           if(StringUtils.isEmpty(po.getStopCmd())){
               //没有则默认用停止命令
               SshUtils.killJarCmd(po.getServerIp(),po.getLoginPort(),po.getLoginUser(),po.getLoginPwd(),po.getJarName());
           }else {
              SshUtils.execForStr(po.getServerIp(),po.getLoginPort(),po.getLoginUser(),po.getLoginPwd(),po.getStopCmd());
           }
        }
        return null;
    }

    @Override
    public String reStart(List<Integer> appServerIdList) {
        stopCmd(appServerIdList);
        startCmd(appServerIdList);
        return null;
    }

    @Override
    public void downLog(List<Integer> appServerIdList, String nextPath, HttpServletResponse response)  {
        List<AppServerPo> appServerPoList = appServerDao.listAppPoById(appServerIdList);
        //处理
        String localBasicPath =  commonComponent.findAppLogPathAtLocal(new Date()) + appServerPoList.get(0).getAppCode()+File.separator;
       for(AppServerPo po : appServerPoList){
           String remoterPath = SFTPUtil.trimFilePath(po.getLogPath()) + SFTPUtil.trimFilePath(nextPath);
           String localPath = localBasicPath +  SFTPUtil.trimFilePath(nextPath);
           SFTPUtil.downMore(po.getServerIp(),po.getLoginPort(),po.getLoginUser(),po.getLoginPwd(),remoterPath,localPath);
       }
       //压缩
        ZipUtil.zip(localBasicPath);

       //下载
        File zipFile = new File(commonComponent.findAppLogPathAtLocal(new Date())+appServerPoList.get(0).getAppCode()+".zip");

        // 设置响应头
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=" + zipFile.getName());
        response.setContentLengthLong(zipFile.length());

        // 通过输入流读取文件内容并写入响应
        OutputStream outputStream = null;
        try {
            FileInputStream inputStream = new FileInputStream(zipFile);
            outputStream = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            }catch (Exception e2){
                e2.printStackTrace();
            }

        }
    }

    /**
     * 查询应用变量
     * @param appIdList
     * @return
     */
    private Map<Integer,Map<String,Object>>  findAppVaris(List<Integer> appIdList){
        List<TAppVari> variList = tAppVariDao.selectList(
                new LambdaQueryWrapper<TAppVari>()
                .in(TAppVari::getAppId,appIdList)
        );
        if(CollectionUtil.isEmpty(variList)){
            return new HashMap<>();
        }

        Map<Integer,List<TAppVari>>  appGroupMap = variList.stream().collect(
                Collectors.groupingBy(TAppVari::getAppId)
        );
        Map<Integer,Map<String,Object>> retMap = new HashMap<>();
        for(Map.Entry<Integer,List<TAppVari>> e : appGroupMap.entrySet()){

            Map<String,Object> map = new HashMap<>();
            for(TAppVari t : e.getValue()){
                map.put(t.getVariKey(),t.getVariActValue());
            }
            retMap.put(e.getKey(),map);
        }
        return retMap;
    }


    private void addApp(TApp app,Map<String,Object> varMap){
        //新增App
        app.setCreateTime(new Date());
        save(app);

        //保存应用分组
        TGroupRelation groupRelation = new TGroupRelation();
        groupRelation.setRelationId(app.getId());
        groupRelation.setGroupId(app.getLongGroup());
        groupRelation.setRelationType(GroupEnums.APP_GROUP.getType());
        getGroupRelationDao.insert(groupRelation);

        //保存应用服务器
        if(StringUtils.isNotEmpty(app.getAppServers())){
            for(String serverId: app.getAppServers().split(",")){
                if(StringUtils.isNotEmpty(serverId)){
                    appServerDao.insert(new TAppServer(null,app.getId(),Integer.parseInt(serverId)));
                }
            }
        }

        //保存变量
        for(Map.Entry<String,Object> e  : varMap.entrySet()){
            TAppVari tv = new TAppVari();
            tv.setAppId(app.getId());
            tv.setVariKey(e.getKey());
            tv.setVariActValue((String)e.getValue());
            tAppVariDao.insert(tv);
        }
    }

    private void updateApp(TApp app,Map<String,Object> varMap){
        //修改App
        app.setUpdateTime(new Date());
        updateById(app);

        //修改分组
        getGroupRelationDao.delete(new LambdaQueryWrapper<TGroupRelation>()
                .eq(TGroupRelation::getRelationId,app.getId())
                .eq(TGroupRelation::getRelationType,GroupEnums.APP_GROUP.getType())
        );

        TGroupRelation groupRelation = new TGroupRelation();
        groupRelation.setRelationId(app.getId());
        groupRelation.setGroupId(app.getLongGroup());
        groupRelation.setRelationType(GroupEnums.APP_GROUP.getType());
        getGroupRelationDao.insert(groupRelation);

        //保存应用服务器
        appServerDao.delete(new LambdaQueryWrapper<TAppServer>()
                .eq(TAppServer::getAppId,app.getId())
        );
        if(StringUtils.isNotEmpty(app.getAppServers())){
            for(String serverId: app.getAppServers().split(",")){
                if(StringUtils.isNotEmpty(serverId)){
                    appServerDao.insert(new TAppServer(null,app.getId(),Integer.parseInt(serverId)));
                }
            }
        }



        //修改变量
        tAppVariDao.delete(new LambdaQueryWrapper<TAppVari>().eq(TAppVari::getAppId,app.getId()));
        for(Map.Entry<String,Object> e  : varMap.entrySet()){
            TAppVari tv = new TAppVari();
            tv.setAppId(app.getId());
            tv.setVariKey(e.getKey());
            tv.setVariActValue((String)e.getValue());
            tAppVariDao.insert(tv);
        }
    }

}

